home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / ddj0290.arc / SCHULMAN.LST < prev    next >
File List  |  1990-01-07  |  21KB  |  705 lines

  1. _STALKING GENERAL PROTECTION FAULTS: PART II_
  2. by Andrew Schulman
  3.  
  4. NOTE: LISTINGS ONE THROUGH THREE WERE PUBLISHED IN THE JANUARY
  5. 1990 ISSUE OF DDJ AND ON-LINE LISTINGS CAN BE FOUND IN THAT AREA
  6.  
  7.  
  8. [LISTING FOUR]
  9.  
  10. /* GPF386.C -- for Phar Lap 386|DOS-Extender and Watcom C 386 7.0
  11. wcl386 -DPROT_MODE -3r -mf -Ox -s gpf386 
  12. wdisasm gpf386 > gpf386.asm
  13. run386 gpf386
  14. NOTE!  To keep this example short, most of the precautions taken
  15. in Listing 3 are not repeated here.  Refer to Listing 3 (GPFAULT.C)
  16. for how the interrupt handler should really be written. */
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include <setjmp.h>
  23. #include <dos.h>
  24. #include "gpfault.h"
  25.  
  26. void reset_pharlap(void);
  27. void prot_far *getvect_prot(short intno);
  28. void real_far *getvect_real(short intno);
  29. BOOL setvect_prot(short intno, void prot_far *handler);
  30. BOOL setvect_real(short intno, void real_far *handler);
  31. BOOL setvect(short intno, void prot_far *handler);
  32. BOOL set2vect(short intno, void prot_far *phandler, void real_far *rhandler);
  33. void revert(void);          // reinstall default handler
  34. void interrupt far int13handler(REG_PARAMS r);
  35. unsigned xtoi(char *s);
  36.  
  37. void prot_far *old_int13handler_prot;
  38. void real_far *old_int13handler_real;
  39. jmp_buf toplevel;
  40. unsigned legal = 0;         // just a legal address to bang on
  41. BOOL in_user_code = FALSE;
  42.  
  43. #define USE16           0x66
  44. #define INT             0xcd
  45. #define PUSH_DS         0x1e
  46. #define POP_DS          0x1f
  47. #define MOV_AX          USE16 0xb8
  48. #define MOV_DS_ES       0x8c 0xc0 0x8e 0xd8      // MOV AX,ES/MOV DS,AX
  49. #define XOR_AL          0x34
  50. #define MOV_AX_CARRYFL  0x9c 0x58 XOR_AL 0x01   // PUSHF/POP AX/XOR AL,1
  51. #define STI             0xfb
  52.  
  53. /* directives for compiler to generate inline code */
  54. #pragma aux reset_pharlap = MOV_AX 0x01 0x25 /* 0x2501 */ INT 0x21 ;
  55. #pragma aux getvect_prot = MOV_AX 0x02 0x25 /* 0x2502 */ INT 0x21 \
  56.     parm [cl] value [ebx es] ;
  57.  /*
  58.     explanation of #pragma aux:  the preceding says that getvect_prot()
  59.     takes one parameter in CL register, and returns value in ES:EBX.
  60.     The "function" itself sets AX to 0x2502 and does an INT 0x21.
  61.     When called: old_int13handler_prot = getvect_prot(0x0D);
  62.     the compiler generates:
  63.         mov cl, 0dh
  64.         mov ax, 2502h
  65.         int 21h
  66.         mov old_int13handler_prot+4, es
  67.         mov old_int13handler_prot, ebx
  68. */
  69.  
  70. #pragma aux getvect_real = MOV_AX 0x03 0x25 /* 0x2503 */ INT 0x21 \
  71.     parm [cl] value [ebx] ;
  72. #pragma aux setvect_real = \
  73.     MOV_AX 0x05 0x25 /* 0x2505 */ \
  74.     INT 0x21 \
  75.     MOV_AX_CARRYFL \
  76.     parm [cl] [ebx] value ;
  77. #pragma aux setvect_prot = \
  78.     PUSH_DS \
  79.     MOV_DS_ES \
  80.     MOV_AX 0x04 0x25 /* 0x2504 */ \
  81.     INT 0x21 \
  82.     POP_DS \
  83.     MOV_AX_CARRYFL \
  84.     parm [cl] [es edx] value ;
  85. #pragma aux setvect = \
  86.     PUSH_DS \
  87.     MOV_DS_ES \
  88.     MOV_AX 0x06 0x25 /* 0x2506 */ \
  89.     INT 0x21 \
  90.     POP_DS \
  91.     MOV_AX_CARRYFL \
  92.     parm [cl] [es edx] value ;
  93. #pragma aux set2vect = \
  94.     PUSH_DS \
  95.     MOV_DS_ES \
  96.     MOV_AX 0x07 0x25 /* 0x2507 */ \
  97.     INT 0x21 \
  98.     POP_DS \
  99.     MOV_AX_CARRYFL \
  100.     parm [cl] [es edx] [ebx] value ;
  101.  
  102. main()
  103. {
  104.     char buf[255];
  105.     unsigned prot_far *fp;
  106.     unsigned short seg;
  107.     unsigned off, data;
  108.  
  109.     old_int13handler_real = getvect_real(0x0D);
  110.     old_int13handler_prot = getvect_prot(0x0D);
  111.     setvect(0x0D, (void prot_far *) int13handler);
  112.     
  113.     printf("'Q' to quit, '!' to reinstall default GP Fault handler\n");
  114.     printf("%Fp is a legal address to poke\n", (void far *) &legal);
  115.     printf("%Fp is not a legal address to poke\n", (void far *) (&legal-1));
  116.     
  117.     setjmp(toplevel);
  118.     
  119.     for (;;)
  120.     {
  121.         printf("$ ");
  122.         *buf = '\0';
  123.         gets(buf);
  124.         if (toupper(*buf) == 'Q')
  125.             break;
  126.         else if (*buf == '!')
  127.         {
  128.             revert();
  129.             continue;
  130.         }
  131.         // got bored of using sscanf()
  132.         seg = xtoi(strtok(buf, ": \t"));
  133.         off = xtoi(strtok(0, " \t"));
  134.         data = xtoi(strtok(0, " \t"));
  135.         in_user_code = TRUE;
  136.         fp = MK_FP(seg, off);       // is this really user code?
  137.         *fp = data;
  138.         printf("poked %Fp with %x\n", fp, *fp);
  139.         in_user_code = FALSE;
  140.     }
  141.     revert();
  142.     printf("Bye\n");
  143.     return 0;
  144. }
  145. void revert(void)
  146. {
  147.     if (! set2vect(0x0d, old_int13handler_prot, old_int13handler_real))
  148.         printf("Can't revert!\n");
  149. }
  150. void interrupt far int13handler(REG_PARAMS r)
  151. {
  152.     _enable();
  153.     reset_pharlap();
  154.     if (in_user_code)
  155.     {
  156.         in_user_code = FALSE;
  157.         printf("\nProtection violation at %04X:%08X\n", 
  158.             r.cs, r.ip);
  159.         if (r.err_code)
  160.             printf("Error code %04X\n", r.err_code);
  161.         printf("<DS %04X> <ES %04X> <FS %04X> <GS %04X>\n", 
  162.             r.ds, r.es, r.fs, r.gs);
  163.         printf("<EDI %08X> <ESI %08X> <FLAGS %08X>\n", 
  164.             r.di, r.si, r.flags);
  165.         printf("<EAX %08X> <EBX %08X> <ECX %08X> <EDX %08X>\n", 
  166.             r.ax, r.bx, r.cx, r.dx);
  167.         longjmp(toplevel, -1);
  168.         /*NOTREACHED*/
  169.     }
  170.     else
  171.     {
  172.         printf("An internal error has occurred at %04X:%08X\n",
  173.             r.cs, r.ip);
  174.         revert();
  175.         _chain_intr(old_int13handler_prot);
  176.         /*NOTREACHED*/
  177.     }
  178. }
  179. // convert ASCIIZ hex string to integer
  180. unsigned xtoi(char *s)
  181. {
  182.     unsigned i =0, t;
  183.     while (*s == ' ' || *s == '\t') s++;
  184.     for (;;)
  185.     {
  186.         char c = *s;
  187.         if      (c >= '0' && c <= '9') t = 48;
  188.         else if (c >= 'A' && c <= 'F') t = 55;
  189.         else if (c >= 'a' && c <= 'f') t = 87;
  190.         else break;
  191.         i = (i << 4) + (c - t);
  192.         s++;
  193.     }
  194.     return i;
  195. }
  196.  
  197.  
  198. [LISTING FIVE]
  199.  
  200. /* GPF386.C -- for Phar Lap 386|DOS-Extender and MetaWare High C for 386 MS-DOS
  201. set ipath=\c386\inc\
  202. \c386\hc386 gpfault -define PROT_MODE
  203. \pharlap\fastlink gpfault -lib small\hce.lib
  204. \pharlap\run386 gpfault
  205. NOTE!  To keep this example short, most of the precautions taken
  206. in Listing 3 are not repeated here.  Refer to Listing 3 (GPFAULT.C)
  207. for how the interrupt handler should really be written.
  208. */
  209.  
  210. #include <stdio.h>
  211. #include <stdlib.h>
  212. #include <ctype.h>
  213. #include <setjmp.h>
  214. #include "msdos.cf"
  215. #include "interrup.cf"
  216. #include "gpfault.h"
  217.  
  218. BOOL call_pharlap(unsigned short ax, unsigned short cl);
  219. void reset_pharlap(void);
  220. IPROC getvect_prot(short intno);
  221. void real_far *getvect_real(short intno);
  222. BOOL setvect_prot(short intno, void prot_far *handler);
  223. BOOL setvect_real(short intno, void real_far *handler);
  224. BOOL setvect(short intno, IPROC handler);
  225. BOOL set2vect(short intno, IPROC phandler, void real_far *rhandler);
  226. void revert(void);  /* install old handlers */
  227.  
  228. #pragma Calling_convention(C_interrupt | _FAR_CALL);
  229. void int13handler(REG_PARAMS r);
  230. #pragma Calling_convention();
  231.  
  232. IPROC old_int13handler_prot;
  233. void real_far *old_int13handler_real;
  234. jmp_buf toplevel;
  235. REG_PARAMS r2 = {0};
  236. BOOL in_user_code = FALSE;
  237.  
  238. main()
  239. {
  240.     char buf[255];
  241.     unsigned prot_far *fp;
  242.     unsigned short seg;
  243.     unsigned off, data;
  244.  
  245.     old_int13handler_real = getvect_real(0x0D);
  246.     old_int13handler_prot = getvect_prot(0x0D);
  247.     setvect(INT_GPFAULT, int13handler);
  248.  
  249.     printf("'Q' to quit, '!' to reinstall default GP Fault handler\n");
  250.     
  251.     if (setjmp(toplevel) == -1)
  252.     {
  253.         printf("Protection violation at %04X:%08X\n", 
  254.             r2.cs, r2.ip);
  255.         if (r2.err_code)
  256.             printf("Error code %04X\n", r2.err_code);
  257.         printf("<ES %04X> <DS %04X> <EDI %08X> <ESI %08X> <FLAGS %08X>\n", 
  258.             r2.es, r2.ds, r2.di, r2.si, r2.flags);
  259.         printf("<EAX %08X> <EBX %08X> <ECX %08X> <EDX %08X>\n", 
  260.             r2.ax, r2.bx, r2.cx, r2.dx);
  261.     }
  262.     for (;;)
  263.     {
  264.         printf("$ ");
  265.         *buf = '\0';
  266.         gets(buf);
  267.         
  268.         if (toupper(*buf) == 'Q')
  269.             break;
  270.         else if (*buf == '!')
  271.         {
  272.             revert();
  273.             continue;
  274.         }
  275.         sscanf(buf, "%04X:%08X %x", &seg, &off, &data);
  276.         FP_SEG(fp) = seg;
  277.         FP_OFF(fp) = off;
  278.         in_user_code = TRUE;
  279.         *fp = data;
  280.         printf("poked %p with %x\n", fp, *fp);
  281.         in_user_code = FALSE;
  282.     }
  283.     revert();
  284.     printf("Bye\n");
  285.     return 0;
  286. }
  287. void revert(void)
  288. {
  289.     set2vect(0x0d, old_int13handler_prot, old_int13handler_real);
  290. }
  291. #pragma Calling_convention(C_interrupt | _FAR_CALL);
  292. void int13handler(REG_PARAMS r)
  293. {
  294.     if (in_user_code)
  295.     {
  296.         in_user_code = FALSE;
  297.         r2 = r;
  298.         reset_pharlap();
  299.         STI;    // _inline(0xFB):  reenable interrupts
  300.         longjmp(toplevel, -1);
  301.     }
  302.     else
  303.     {
  304.         printf("Internal error at %04X:%08X\n", r.cs, r.ip);
  305.         revert();
  306.         return;     // let the fault happen again  (no _chain_intr)
  307.     }
  308.     /*NOTREACHED*/
  309. }
  310. #pragma Calling_convention();
  311. BOOL call_pharlap(unsigned short ax, unsigned short cl)
  312. {
  313.     Registers.AX.W = ax;
  314.     Registers.CX.LH.L = cl;
  315.     calldos();
  316.     return !(Registers.Flags & 1);
  317. }
  318. void reset_pharlap(void)
  319. {
  320.     call_pharlap(0x2501, 0);
  321. }
  322. IPROC getvect_prot(short intno)
  323. {
  324.     IPROC handler;
  325.     call_pharlap(0x2502, intno);
  326.     /* no MK_FP for High C 386 */
  327.     FP_SEG(handler) = Registers.ES.W;
  328.     FP_OFF(handler) = Registers.BX.R;
  329.     return handler;
  330. }
  331. void real_far *getvect_real(short intno)
  332. {
  333.     call_pharlap(0x2503, intno);
  334.     return (void real_far *) Registers.BX.R;
  335. }
  336. BOOL setvect_prot(short intno, void prot_far *handler)
  337. {
  338.     Registers.DS.W = FP_SEG(handler);
  339.     Registers.DX.R = FP_OFF(handler);
  340.     return call_pharlap(0x2504, intno);
  341. }
  342. BOOL setvect_real(short intno, void real_far *handler)
  343. {
  344.     Registers.BX.R = (unsigned) handler;
  345.     return call_pharlap(0x2505, intno);
  346. }
  347. BOOL setvect(short intno, IPROC handler)
  348. {
  349.     Registers.DS.W = FP_SEG(handler);
  350.     Registers.DX.R = FP_OFF(handler);
  351.     return call_pharlap(0x2506, intno);
  352. }
  353. BOOL set2vect(short intno, IPROC phandler, void real_far *rhandler)
  354. {
  355.     Registers.DS.W = FP_SEG(phandler);
  356.     Registers.DX.R = FP_OFF(phandler);
  357.     Registers.BX.R = (unsigned) rhandler;
  358.     return call_pharlap(0x2507, intno);
  359. }
  360.  
  361.  
  362. [LISTING SIX]
  363.  
  364. /* OS2TRACE.C -- catching GP faults in OS/2, using DosPTrace()
  365. compile with:
  366.     cl -Lp os2trace.c
  367. to make tiny (less than 3K) .EXE with C run-time DLL, compile with:
  368.     cl -AL -c -Gs2 -Ox -Lp -I\msc\inc\mt os2trace.c
  369.     link /nod/noi crtexe.obj os2trace,os2trace,,crtlib.lib \os2\lib\os2.lib;
  370. */
  371.  
  372. #include <stdio.h>
  373. #include <string.h>
  374. #include <process.h>
  375. #include <signal.h>
  376. #include <setjmp.h>
  377.  
  378. #define INCL_DOS
  379. #define INCL_DOSTRACE
  380. #define INCL_VIO
  381. #include "os2.h"
  382. #include "ptrace.h"
  383.  
  384. #define LOCAL static
  385. typedef unsigned WORD;
  386.  
  387. LOCAL VOID NEAR print_regs(void);
  388. LOCAL VOID NEAR send_sig_segv(void);
  389. LOCAL VOID NEAR catch_sig_segv(void);
  390. LOCAL WORD NEAR trace(int argc, char *argv[], BOOL verbose);
  391. LOCAL VOID NEAR start_trace(char *prog, char *cmdline);
  392. LOCAL char *progname(char *s);
  393. LOCAL char *cmdline(int argc, char *argv[]);
  394. LOCAL WORD NEAR selector_from_segment(WORD seg);
  395. LOCAL VOID NEAR set_csip(WORD cs, WORD ip);
  396. LOCAL int break_handler(void);
  397.  
  398. PTRACEBUF ptb;
  399. jmp_buf toplevel;
  400.  
  401. #define FP_OFF(fp)      ((unsigned) (fp))
  402.  
  403. #define JMP_GPFAULT     -1
  404. #define JMP_BREAK       -2
  405.  
  406. main(int argc, char *argv[])
  407. {
  408.     char buf[80];
  409.     BOOL do_trace = TRUE;
  410.     BOOL verbose = FALSE;
  411.     WORD x;
  412.     int i;
  413.     for (i=1; i<argc; i++)
  414.         if (argv[i][0] == '-')
  415.             switch(argv[i][1])
  416.             {
  417.                 case 'x': do_trace = FALSE; break;
  418.                 case 'v': verbose = TRUE;   break;
  419.             }
  420.     signal(SIGINT, break_handler);  // doesn't work with CRTLIB.DLL
  421.     if (do_trace)
  422.         return trace(argc, argv, verbose);
  423.     // if (! do_trace) run interpreter
  424.     switch (setjmp(toplevel))   // used to catch multiple events
  425.     {
  426.         case JMP_GPFAULT:
  427.             printf("General Protection violation!\n");  
  428.             break;
  429.         case JMP_BREAK:
  430.             printf("break\n");
  431.             signal(SIGINT, break_handler);
  432.             // what if this is trace process??
  433.             break;
  434.     }
  435.     for (;;)
  436.     {
  437.         printf("$ ");
  438.         gets(buf);
  439.         if (toupper(*buf) == 'Q')
  440.             break;
  441.         // cause one of a number of different GP faults
  442.         switch (*buf)
  443.         {
  444.             case '0': x = *((int far *) 0L);        break;  // GP fault
  445.             case '1': x = *((int far *) -1L);       break;  // GP fault
  446.             case '2': *((char *) main) = 'x';       break;  // bashes data!
  447.             case '3': x = VioWrtTTY(0L, 100, 0);    break;  // GP fault in DLL
  448.             case '4': x = VioWrtTTY(-1L, 100, 0);   break;  // GP fault in DLL
  449.             case '5': x = VioWrtTTY(0L);            break;  // boom!
  450.             case '6': x = puts(-1L);                break;  // GP fault
  451.             case '7': x = DosGetInfoSeg(1L, 2L);    break;  // thread dies
  452.         }
  453.         printf("Executed statement %c\n", *buf);
  454.     }
  455.     return 0;
  456. }
  457. /*  case 2 is important because, though the operation is illegal, it does
  458.     not generate a GP fault.  Consequently, the operation is successful.
  459.     Depending on how OS2TRACE.C is compiled, sometimes a string gets bashed
  460.     so that string prints out "General protection vixlation," sometimes
  461.     something else gets bashed so that when we exit, C run-time puts up
  462.     message about null pointer assignment.
  463. */
  464. LOCAL WORD NEAR trace(int argc, char *argv[], BOOL verbose)
  465. {
  466.     start_trace(progname(argv[0]), cmdline(argc, argv));
  467.     /* DosPTrace event loop */
  468.     for (;;)
  469.     {
  470.         ptb.tid = 0;
  471.         ptb.cmd = GO;
  472.         DosPTrace(&ptb);
  473.         switch (ptb.cmd)
  474.         {
  475.             case EVENT_GP_FAULT:
  476.                if (verbose)
  477.                {
  478.                    printf("GP fault (error %04X) at %04X:%04X\n",
  479.                         ptb.value, ptb.segv, ptb.offv);
  480.                    print_regs();
  481.                }
  482.                send_sig_segv();
  483.                break;
  484.            case EVENT_THREAD_DEAD:
  485.                if (verbose)
  486.                     printf("Thread %u dying\n", ptb.tid);
  487.                break;
  488.            case EVENT_DYING:
  489.                if (verbose)
  490.                    printf("Process %u dying\n", ptb.pid);
  491.                return 0;
  492.         }
  493.     }
  494.     /*NOTREACHED*/
  495. }
  496. LOCAL VOID NEAR print_regs(void)
  497. {
  498.      ptb.cmd = READ_REGISTERS;
  499.      DosPTrace(&ptb);
  500.      printf("AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X BP=%04X\n",
  501.          ptb.rAX, ptb.rBX, ptb.rCX, ptb.rDX, ptb.rSI, ptb.rDI, ptb.rBP);
  502.      printf("DS=%04X ES=%04X IP=%04X CS=%04X FL=%04X SP=%04X SS=%04X\n",
  503.          ptb.rDS, ptb.rES, ptb.rIP, ptb.rCS, ptb.rF,  ptb.rSP, ptb.rSS);
  504. }
  505. LOCAL VOID NEAR send_sig_segv(void)
  506. {
  507.     /* because of OS/2 "disjoint LDT space," we could just as easily say:
  508.         WORD cs = FP_SEG((void far *) catch_sig_segv);
  509.     it will be mapped to same selector in both processes
  510.     */
  511.     WORD cs = selector_from_segment(1);     // catch_sig_segv() in seg 1
  512.     WORD ip = FP_OFF((void far *) catch_sig_segv);
  513.     set_csip(cs, ip);
  514. }
  515. LOCAL WORD NEAR selector_from_segment(WORD seg)
  516. {
  517.     ptb.value = seg;
  518.     ptb.cmd = SEG_NUM_TO_SELECTOR;
  519.     DosPTrace(&ptb);
  520.     return (ptb.cmd == EVENT_ERROR) ? 0 : ptb.value;
  521. }
  522. LOCAL VOID NEAR set_csip(WORD cs, WORD ip)
  523. {
  524.     ptb.cmd = READ_REGISTERS;
  525.     DosPTrace(&ptb);
  526.     ptb.rCS = cs;
  527.     ptb.rIP = ip;
  528.     if (ptb.rDS != ptb.rSS)
  529.     {
  530.         printf("Faulted inside DLL code\n");
  531.         ptb.rDS = ptb.rSS;  // very important!
  532.     }
  533.     ptb.cmd = WRITE_REGISTERS;
  534.     DosPTrace(&ptb);
  535. }
  536. LOCAL VOID NEAR catch_sig_segv(void)
  537. {
  538.     longjmp(toplevel, JMP_GPFAULT);
  539. }
  540. // shared by debugger and debuggee processes
  541. LOCAL int break_handler(void)
  542. {
  543.     signal(SIGINT, SIG_IGN);
  544.     longjmp(toplevel, JMP_BREAK);
  545. }
  546. LOCAL VOID NEAR start_trace(char *prog, char *cmdline)
  547. {
  548.     RESULTCODES resc;
  549.     if (DosExecPgm(NULL, 0, EXEC_TRACE, cmdline, NULL, &resc, prog) != 0)
  550.         return;
  551.     ptb.pid = resc.codeTerminate;
  552.     ptb.tid = 0;
  553. }
  554. // tacks .EXE after program name
  555. LOCAL char *progname(char *s)
  556. {
  557.     static char str[128];
  558.     strcpy(str, s);
  559.     strcat(str, ".EXE");
  560.     return str;
  561. }
  562. // undoes all argc/argv work, appends -x switch
  563. LOCAL char *cmdline(int argc, char *argv[])
  564. {
  565.     static char str[128], *t = str;
  566.     char *s = argv[0];
  567.     register int arg = 0;
  568.     while (arg < argc)
  569.     {
  570.         while (*s) 
  571.             *t++ = *s++;
  572.         *t++ = (arg) ? ' ' : '\0';  // '\0' after program name
  573.         s = argv[++arg];
  574.     }
  575.     *t++ = '-'; *t++ = 'x';         // append -x switch
  576.     *t = '\0';
  577.     return str;
  578. }
  579.  
  580.  
  581.  
  582. [LISTING SEVEN]
  583.  
  584. // ptrace.h
  585.  
  586. // DosPTrace commands
  587. #define READ_I_SPACE            0x0001
  588. #define READ_D_SPACE            0x0002
  589. #define READ_REGISTERS          0x0003
  590. #define WRITE_I_SPACE           0x0004
  591. #define WRITE_D_SPACE           0x0005
  592. #define WRITE_REGISTERS         0x0006
  593. #define GO                      0x0007
  594. #define TERMINATE_CHILD         0x0008
  595. #define SINGLE_STEP             0x0009
  596. #define STOP_CHILD              0x000A
  597. #define FREEZE_CHILD            0x000B
  598. #define RESUME_CHILD            0x000C
  599. #define SEG_NUM_TO_SELECTOR     0x000D
  600. #define GET_FLOATINGPT_REGS     0x000E
  601. #define SET_FLOATINGPT_REGS     0x000F
  602. #define GET_DLL_NAME            0x0010
  603. #define THREAD_STATUS           0x0011   // new
  604. #define MAP_READONLY_ALIAS      0x0012
  605. #define MAP_READWRITE_ALIAS     0x0013
  606. #define UNMAP_ALIAS             0x0014
  607.  
  608. // DosPTrace events
  609. #define EVENT_SUCCESS           0
  610. #define EVENT_ERROR             -1
  611. #define EVENT_SIGNAL            -2
  612. #define EVENT_SINGLESTEP        -3
  613. #define EVENT_BREAKPOINT        -4
  614. #define EVENT_PARITYERROR       -5
  615. #define EVENT_DYING             -6
  616. #define EVENT_GP_FAULT          -7
  617. #define EVENT_LOAD_DLL          -8
  618. #define EVENT_FLOATPT_ERROR     -9
  619. #define EVENT_THREAD_DEAD       -10
  620. #define EVENT_ASYNC_STOP        -11
  621. #define EVENT_NEW_PROCESS       -12
  622. #define EVENT_ALIAS_FREE        -13
  623.  
  624. // DosPTrace error types
  625. #define ERROR_BAD_COMMAND       1
  626. #define ERROR_CHILD_NOTFOUND    2
  627. #define ERROR_UNTRACEABLE       5
  628.  
  629. // Thread states
  630. #define THREAD_RUNNABLE         0
  631. #define THREAD_SUSPENDED        1
  632. #define THREAD_BLOCKED          2
  633. #define THREAD_CRITSEC          3
  634.  
  635. // Thread debug states
  636. #define THREAD_THAWED           0
  637. #define THREAD_FROZEN           1
  638.  
  639.  
  640.  
  641. Figurσ 1║ ┴ samplσ sessioε witΦ ß 3▓-bi⌠ versioε oµ thσ G╨ Faul⌠ ì
  642. interpreter
  643.  
  644.         C:\PHARLAP>run386 gpf386
  645.         'Q' to quit, '!' to reinstall default GP fault handler
  646.         0014:000038a4 is a legal address to poke
  647.         0014:000038a0 is not a legal address to poke
  648.         $ 1234:00005678 66666666
  649.         Protection violation at 000C:00000111!
  650.         Error code 1234è        <DS 0014> <ES 000C> <FS 0014> <GS 0014>
  651.         <EDI 00003CC0> <ESI 66666666> <FLAGS 00010297>
  652.         <EAX 00005678> <EBX 00005678> <ECX 00001234> <EDX 00001234>
  653.         $ 000c:00000111 66666666
  654.         Protection violation at 000C:00000127!
  655.         <DS 0014> <ES 000C> <FS 000C> <GS 0014>
  656.         <EDI 0000000C> <ESI 66666666> <FLAGS 00010212>
  657.         <EAX 00000019> <EBX 00000111> <ECX 0000000C> <EDX 0000000C>
  658.         $ 0034:000b80a0 70217021
  659.         poked 0034:000b80a0 with 70217021
  660.  
  661.  
  662. Figurσ 2║ ┴ samplσ sessioε usinτ thσ OS/▓ G╨ Faul⌠ interpreterè
  663.         C:\OS2\PTRACE>os2trace -v
  664.         $ 0     ;; x = *((int far *) 0L);
  665.         GP fault (error 0000) at 0047:01C0
  666.         AX=0030 BX=0000 CX=0000 DX=0087 SI=0087 DI=0001 BP=0CBE
  667.         DS=0087 ES=0000 IP=01C0 CS=0047 FL=2246 SP=0C5A SS=0087
  668.         General Protection violation!
  669.         $ 1     ;; x = *((int far *) -1L);
  670.         GP fault (error FFFC) at 0047:01BE
  671.         AX=0031 BX=FFFF CX=0000 DX=0087 SI=0087 DI=0001 BP=0CBE
  672.         DS=0087 ES=0087 IP=01BE CS=0047 FL=2202 SP=0C5A SS=0087
  673.         General Protection violation!
  674.         $ 2     ;; *((char *) main) = 'x';
  675.         Executed statement 2
  676.         $ 3     ;; x = VioWrtTTY(0L, 100, 0);
  677.         GP fault (error 0000) at 00D7:27F1
  678.         AX=0000 BX=02C4 CX=0051 DX=0000 SI=0087 DI=0051 BP=0C34
  679.         DS=00DF ES=0000 IP=27F1 CS=00D7 FL=2246 SP=0C26 SS=0087
  680.         Faulted inside DLL code
  681.         General Protection vxolation!
  682.         $ 7     ;; x = DosGetInfoSeg(1L, 2L);
  683.         Thread 1 dying
  684.         Process 79 dying
  685.         C:\OS2\PTRACE>
  686.  
  687.  
  688. Figurσ 3║ Aε OS/▓ message¼ differen⌠ froφ norma∞ G╨ faul⌠ dump
  689.  
  690.         Session Title: CVP app OS2TRACE.EXE
  691.             The system detected a general protection
  692.             fault (trap D) in a system call.
  693.             CS=0047 IP=0237 S=0087 SP=0C5A
  694.             ERRCD=0000 ERLIM=**** ERACC=**
  695.             Arguments used in system call (high to low):
  696.             0000 0001 0000 0002
  697.                 End the program
  698.  
  699. Figurσ 4║ Detectinτ IN╘ 0├ unde≥ OS/2
  700.  
  701.             SYS1942:  A program attempted to reference storage
  702.             outside the limits of a stack segment.  The program
  703.             was ended.
  704.             TRAP 000C
  705.